﻿using System;
using System.Collections.Generic;
using System.Text;

namespace eKanbanWPF.Model
{
    [Serializable]
    public class Feature : IEnumerable<Task>, IEnumerable<FeaturePhase>
    {
        public delegate void FeatureChanged(Feature feature);
        public event FeatureChanged Changed;

        private bool done;
        private List<FeaturePhase> history;
        private List<Task> tasks;

        public IList<Task> Tasks { get { return tasks.AsReadOnly(); } }
        public IList<FeaturePhase> History { get { return history.AsReadOnly(); } }

        public Feature()
        {
            tasks = new List<Task>();
            done = false;
            history = new List<FeaturePhase>();
            Description = "";
            Priority = 5;
            Width = 100;
            Height = 100;
        }

        public Feature(BasePhase begin, string name, string description, int priority)
            : this()
        {
            history.Add(new FeaturePhase(begin));
            Name = name;
            Description = description;
            Priority = priority;
            begin.Add(this);
        }
        #region GUI Properties
        public double Left { get; set; }
        public double Top { get; set; }
        public double Width { get; set; }
        public double Height { get; set; }
        #endregion
        #region Properties
        string name;
        public string Name
        {
            get { return name; }
            set
            {
                name = value;
                if (Changed != null)
                {
                    Changed.Invoke(this);
                }
            }
        }
        string description;
        public string Description
        {
            get { return description; }
            set
            {
                description = value;
                if (Changed != null)
                {
                    Changed.Invoke(this);
                }
            }
        }

        int priority;
        public int Priority
        {
            get { return priority; }
            set
            {
                priority = value;
                if (Changed != null)
                {
                    Changed.Invoke(this);
                }
            }
        }

        public BasePhase CurrentPhase { get { return history[history.Count - 1].BasePhase; } }

        public bool Done { get { return done; } set { SetDone(value); } }
        #endregion
        #region featurePhase's Properties
        public DateTime Deadline
        {
            get
            {
                return history[history.Count - 1].DeadLine;
            }
            set
            {
                //FeaturePhase tmp = history[history.Count - 1];
                //if (tmp.StartTime >= value)
                //{
                //    throw new Exception("Cannot set deadline <= startTime");
                //}
                history[history.Count - 1].DeadLine = value;
            }
        }

        public DateTime StartTime
        {
            get
            {
                return history[history.Count - 1].StartTime;
            }
            set
            {
                FeaturePhase tmp = history[history.Count - 1];
                if (tmp.FinishTime <= value && tmp.FinishTime != DateTime.MaxValue)
                {
                    throw new Exception("Cannot set startTime >= finishTime");
                }
                //if (tmp.DeadLine <= value && tmp.DeadLine != DateTime.MinValue)
                //{
                //    throw new Exception("Cann not set startTime >= deadline");
                //}
                history[history.Count - 1].StartTime = value;
            }
        }

        public DateTime FinishTime
        {
            get
            {
                return history[history.Count - 1].FinishTime;
            }
            set
            {
                FeaturePhase tmp = history[history.Count - 1];
                if (tmp.StartTime >= value)
                {
                    throw new Exception("Cannot set finishTime <= startTime");
                }
                history[history.Count - 1].DeadLine = value;
            }
        }
        #endregion
        //all tasks are completed and user set this feature is done

        private void SetDone(bool value)
        {
            if (!value)
            {
                done = value;
            }
            else
            {
                bool ck = true;
                foreach (Task item in tasks)
                {
                    if (!item.Done)
                    {
                        ck = false;
                        break;
                    }
                }
                if (ck)
                {
                    done = value;
                    if (Changed != null)
                    {
                        Changed.Invoke(this);
                    }
                }
                else
                {
                    throw new Exception("Some tasks are not completed!!!");
                }
            }
        }

        public bool CanMove(BasePhase nextPhase)
        {
            //feature cannot move when still has on going task(s)
            foreach (Task item in tasks)
            {
                if (item.OnGoing)
                {
                    return false;
                }
            }

            //validate if feature in current phase can move to nextPhase
            if (!CurrentPhase.CanMove(nextPhase) && !CurrentPhase.CanMoveBack(nextPhase))
            {
                return false;
            }

            //validate if current phase can remove this feature
            if (!CurrentPhase.CanRemove(this))
            {
                return false;
            }

            //validate if next phase can add this feature
            if (!nextPhase.CanAdd(this))
            {
                return false;
            }

            return true;
        }

        public void Move(BasePhase nextPhase)
        {
            //check if this feature can move to nextPhase
            if (!CanMove(nextPhase))
            {
                throw new Exception("Can't move to " + nextPhase);
            }
            //remove this feature out of current phase and update history
            history[history.Count - 1].FinishTime = DateTime.Now.Date;
            CurrentPhase.Remove(this);
            //add this feature to newPhase
            history.Add(new FeaturePhase(nextPhase));
            CurrentPhase.Add(this);
        }

        public void AddNewTask(Task newTask)
        {
            if (!tasks.Contains(newTask))
            {
                tasks.Add(newTask);
                newTask.Feature = this;
            }
        }

        public void RemoveTask(Task task)
        {
            if (tasks.Contains(task))
            {
                tasks.Remove(task);
                task.Feature = null;
            }
        }

        public override string ToString()
        {
            return Name;
            //string str = String.Format("Feature: {0}\nPriority: {1}\nHistory", Description, Priority);
            //foreach (FeaturePhase item in history)
            //{
            //    //str += "\n\tPhase: " + item.BasePhase.Name;
            //    //str += "\n\tStart: " + item.StartTime;
            //    //str += "\n\tFinish: " + item.FinishTime;
            //    //str += "\n\tDeadLine: " + item.DeadLine;
            //    str += String.Format("\n{0}\n", item);
            //}
            //str += "\nTasks:";
            //foreach (Task item in tasks)
            //{
            //    //str += "\n\tDesc: " + item.Description;
            //    //str += "\n\tStart: " + item.StartTime;
            //    //str += "\n\tFinish: " + item.FinishTime;
            //    //str += "\n\tDeadLine: " + item.DeadLine;
            //    //str += "\n\tStatus: " + item.Status;
            //    str += String.Format("\n{0}\n", item);
            //}
            //return str;
        }

        public IEnumerator<Task> GetEnumerator()
        {
            return tasks.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            throw new NotImplementedException();
        }

        IEnumerator<FeaturePhase> IEnumerable<FeaturePhase>.GetEnumerator()
        {
            return history.GetEnumerator();
        }
    }
}
